package pushlog

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"net/url"
	"time"

	"gitee.com/xuesongtao/collect/library"

	"github.com/gogf/gf/frame/g"
)

const (
	ErrLogType     uint8 = iota // err log
	GeneralLogType              // 正常 log
)

// API: https://developers.dingtalk.com/document/robots/custom-robot-access

type DingDing struct {
	pushUrl string
	cli     *library.HttpCli
	Req     library.BodyMap
}

func NewDingDing(bodyMapSize int, pushUrl string) *DingDing {
	return &DingDing{
		pushUrl: pushUrl,
		cli:     library.NewHttpCli(),
		Req:     library.NewBodyMap(bodyMapSize),
	}
}

func (d *DingDing) getSign() (int64, string) {
	curTimestamp := time.Now().UnixNano() / 1e6
	dingdingSecret := library.DecFn(g.Cfg().GetString("dingding.dingding_secret"))
	sign := []byte(fmt.Sprintf("%d\n%s", curTimestamp, dingdingSecret))
	hmacObj := hmac.New(sha256.New, []byte(dingdingSecret))
	hmacObj.Write(sign)
	encodeStr := base64.StdEncoding.EncodeToString(hmacObj.Sum(nil))
	return curTimestamp, url.QueryEscape(encodeStr)
}

func (d *DingDing) PushText(logType uint8, title PushTitle, content string, at ...library.BodyMap) (*library.HttpCliResp, error) {
	// 将 appName 通过 fmt 替换
	val := library.NewBodyMap(3).Set("content", title+"\n"+content)

	atLen := len(at)
	if atLen > 0 {
		d.Req.Set("at", at[0])
	}

	if logType == ErrLogType && atLen == 0 { // 如果是错误消息就 @all
		d.Req.Set("at", library.NewBodyMap(2).Set("isAtAll", true))
	}

	d.Req.Set("msgtype", TextForReq).Set(TextForReq, val)
	return d.push()
}

func (d *DingDing) PushMarkdown(logType uint8, title PushTitle, markdown string, at ...library.BodyMap) (*library.HttpCliResp, error) {
	// 将 appName 通过 fmt 替换
	val := library.NewBodyMap(3).Set("title", title).Set("text", markdown)

	atLen := len(at)
	if atLen > 0 {
		d.Req.Set("at", at[0])
	}

	if logType == ErrLogType && atLen == 0 { // 如果是错误消息就 @all
		d.Req.Set("at", library.NewBodyMap(2).Set("isAtAll", true))
	}

	d.Req.Set("msgtype", MarkdownForReq).Set(MarkdownForReq, val)
	return d.push()
}

func (d *DingDing) Push(req library.BodyMap) (*library.HttpCliResp, error) {
	d.Req = req
	return d.push()
}

func (d *DingDing) push() (*library.HttpCliResp, error) {
	body, err := d.Req.Marshal()
	if err != nil {
		return nil, err
	}
	timestamp, sign := d.getSign()
	pushUrl := d.pushUrl + fmt.Sprintf("&timestamp=%d&sign=%v", timestamp, sign)
	return d.cli.Post(pushUrl, body)
}
